#include "GameList.hh"
#include "XmlClient.hh"
#include "../Exception.hh"

using namespace Network;

spGameList GameList::construct(GameListInfo const& gameListInfo) {
    return spGameList(new GameList(gameListInfo));
}

spGameList GameList::construct(QDomElement const& message) {
    GameListInfo gameListInfo;
    QDomElement game = message.firstChildElement("game");

    while (!game.isNull()) {
        QDomElement name = game.firstChildElement("name");
        QDomNode nameNode = name.firstChild();
        QDomText nameText = nameNode.toText();
        QString nameStr = nameText.nodeValue();
        QDomElement players = game.firstChildElement("players");
        QDomElement player = players.firstChildElement("player");
        PlayerListInfo playerInfo;

        if (game.isNull())
            throw NonFatalProtocolError("game_list.game.name missing");

        if (!nameNode.isText())
            throw NonFatalProtocolError("game_list.game.name invalid");

        if (players.isNull())
            throw NonFatalProtocolError("game_list.game.players missing");

        if (gameListInfo.contains(nameStr))
            throw NonFatalProtocolError("game_list.game.name not unique");

        while (!player.isNull()) {
            QDomNode playerNode = player.firstChild();
            QDomText playerText = playerNode.toText();
            QString playerStr = playerText.nodeValue();

            if (!playerNode.isText())
                throw
                  NonFatalProtocolError(
                    "game_list.game.players.player invalid"
                  );

            if (playerInfo.contains(playerStr))
                throw
                  NonFatalProtocolError(
                    "game_list.game.players.player not unique"
                  );

            playerInfo.insert(playerStr);
            player = player.nextSiblingElement("player");
        }

        GameInfo gameInfo;
        gameInfo.playerListInfo = playerInfo;
        gameListInfo.insert(nameStr, gameInfo);
        game = game.nextSiblingElement("game");
    }

    return construct(gameListInfo);
}

GameList::GameList(GameListInfo const& gameListInfo):
    InitMessage(),
    gameListInfo(gameListInfo) {}

void GameList::process_on_client(XmlClient& client) {
	if(client.get_state() == INIT_GET_GAME_LIST_SENT)
			client.process_game_list(gameListInfo);
	else
		throw NonFatalProtocolError("gamelist unexpected");
}

QDomDocument GameList::to_xml() const {
    QDomDocument doc;
    QDomElement init = doc.createElement("init");
    QDomElement game_list = doc.createElement("game_list");
    doc.appendChild(init);
    init.appendChild(game_list);

    for (
      GameListInfo::const_iterator gameInfo = gameListInfo.begin();
      gameInfo != gameListInfo.end();
      ++gameInfo
    ) {
        QDomElement game = doc.createElement("game");
        QDomElement name = doc.createElement("name");
        QDomElement players = doc.createElement("players");
        QDomText nameText = doc.createTextNode(gameInfo.key());
        game_list.appendChild(game);
        game.appendChild(name);

        if (gameInfo->minPlayers) {
            QDomElement minElem = doc.createElement("min_players");
            QDomText minText =
              doc.createTextNode(QString::number(gameInfo->minPlayers));
            game.appendChild(minElem);
            minElem.appendChild(minText);
        }

        if (gameInfo->maxPlayers != UNLIMITED) {
            QDomElement maxElem = doc.createElement("max_players");
            QDomText maxText =
              doc.createTextNode(QString::number(gameInfo->maxPlayers));
            game.appendChild(maxElem);
            maxElem.appendChild(maxText);
        }

        game.appendChild(players);
        name.appendChild(nameText);

        for (
          PlayerListInfo::const_iterator playerInfo =
            gameInfo->playerListInfo.begin();
          playerInfo != gameInfo->playerListInfo.end();
          ++playerInfo
        ) {
            QDomElement player = doc.createElement("player");
            QDomText playerText = doc.createTextNode(*playerInfo);
            players.appendChild(player);
            player.appendChild(playerText);
        }
    }

    return doc;
}
